Initialization and import of data

install.packages("VGAM")
essai de l'URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/VGAM_1.1-5.tgz'
Content type 'application/x-gzip' length 7281930 bytes (6.9 MB)
==================================================
downloaded 6.9 MB

The downloaded binary packages are in
    /var/folders/6g/jj4zrn8n0pv9nvlgqdvg6k500000gn/T//RtmpT1znVe/downloaded_packages
names(dataSet)
 [1] "battery_power" "blue"          "clock_speed"   "dual_sim"      "fc"            "four_g"        "int_memory"    "m_dep"         "mobile_wt"     "n_cores"       "pc"            "px_height"     "px_width"      "ram"          
[15] "sc_h"          "sc_w"          "talk_time"     "three_g"       "touch_screen"  "wifi"          "price_range"  

Display of the set of data.

Columns : battery_power, blue, clock_speed, dual_sim, fc, four_g,int_memory, m_dep, mobile_wt, n_cores, pc, px_height, px_width, ram, sc_h, sc_w, talk_time, three_g, touch_screen, wifi, price_range

battery_power:Total energy a battery can store in one time measured in mAh blue:Has bluetooth or not clock_speed:speed at which microprocessor executes instructions dual_sim:Has dual sim support or not fc:Front Camera mega pixels four_g:Has 4G or not int_memory:Internal Memory in Gigabytes m_dep:Mobile Depth in cm mobile_wt:Weight of mobile phone n_cores:Number of cores of processor pc:Primary Camera mega pixels px_height:Pixel Resolution Height px_width:Pixel Resolution Width ram:Random Access Memory in Megabytes sc_h:Screen Height of mobile in cm sc_w:Screen Width of mobile in cm talk_time:longest time that a single battery charge will last when you are three_g:Has 3G or not touch_screen:Has touch screen or not wifi:Has wifi or not price_range: This is the target variable with value of 0(low cost), 1(medium cost), 2(high cost) and 3(very high cost).

dim(dataSet)
[1] 2000   21
class(dataSet)
[1] "data.frame"
head(dataSet)
sapply(dataSet, class)
battery_power          blue   clock_speed      dual_sim            fc        four_g    int_memory         m_dep     mobile_wt       n_cores            pc     px_height      px_width           ram          sc_h          sc_w     talk_time 
    "integer"     "integer"     "numeric"     "integer"     "integer"     "integer"     "integer"     "numeric"     "integer"     "integer"     "integer"     "integer"     "integer"     "integer"     "integer"     "integer"     "integer" 
      three_g  touch_screen          wifi   price_range 
    "integer"     "integer"     "integer"     "integer" 
summary(dataSet)
 battery_power         blue        clock_speed       dual_sim            fc             four_g         int_memory        m_dep          mobile_wt        n_cores            pc           px_height         px_width           ram      
 Min.   : 501.0   Min.   :0.000   Min.   :0.500   Min.   :0.0000   Min.   : 0.000   Min.   :0.0000   Min.   : 2.00   Min.   :0.1000   Min.   : 80.0   Min.   :1.000   Min.   : 0.000   Min.   :   0.0   Min.   : 500.0   Min.   : 256  
 1st Qu.: 851.8   1st Qu.:0.000   1st Qu.:0.700   1st Qu.:0.0000   1st Qu.: 1.000   1st Qu.:0.0000   1st Qu.:16.00   1st Qu.:0.2000   1st Qu.:109.0   1st Qu.:3.000   1st Qu.: 5.000   1st Qu.: 282.8   1st Qu.: 874.8   1st Qu.:1208  
 Median :1226.0   Median :0.000   Median :1.500   Median :1.0000   Median : 3.000   Median :1.0000   Median :32.00   Median :0.5000   Median :141.0   Median :4.000   Median :10.000   Median : 564.0   Median :1247.0   Median :2146  
 Mean   :1238.5   Mean   :0.495   Mean   :1.522   Mean   :0.5095   Mean   : 4.309   Mean   :0.5215   Mean   :32.05   Mean   :0.5018   Mean   :140.2   Mean   :4.521   Mean   : 9.916   Mean   : 645.1   Mean   :1251.5   Mean   :2124  
 3rd Qu.:1615.2   3rd Qu.:1.000   3rd Qu.:2.200   3rd Qu.:1.0000   3rd Qu.: 7.000   3rd Qu.:1.0000   3rd Qu.:48.00   3rd Qu.:0.8000   3rd Qu.:170.0   3rd Qu.:7.000   3rd Qu.:15.000   3rd Qu.: 947.2   3rd Qu.:1633.0   3rd Qu.:3064  
 Max.   :1998.0   Max.   :1.000   Max.   :3.000   Max.   :1.0000   Max.   :19.000   Max.   :1.0000   Max.   :64.00   Max.   :1.0000   Max.   :200.0   Max.   :8.000   Max.   :20.000   Max.   :1960.0   Max.   :1998.0   Max.   :3998  
      sc_h            sc_w          talk_time        three_g        touch_screen        wifi        price_range  
 Min.   : 5.00   Min.   : 0.000   Min.   : 2.00   Min.   :0.0000   Min.   :0.000   Min.   :0.000   Min.   :0.00  
 1st Qu.: 9.00   1st Qu.: 2.000   1st Qu.: 6.00   1st Qu.:1.0000   1st Qu.:0.000   1st Qu.:0.000   1st Qu.:0.75  
 Median :12.00   Median : 5.000   Median :11.00   Median :1.0000   Median :1.000   Median :1.000   Median :1.50  
 Mean   :12.31   Mean   : 5.767   Mean   :11.01   Mean   :0.7615   Mean   :0.503   Mean   :0.507   Mean   :1.50  
 3rd Qu.:16.00   3rd Qu.: 9.000   3rd Qu.:16.00   3rd Qu.:1.0000   3rd Qu.:1.000   3rd Qu.:1.000   3rd Qu.:2.25  
 Max.   :19.00   Max.   :18.000   Max.   :20.00   Max.   :1.0000   Max.   :1.000   Max.   :1.000   Max.   :3.00  
library(ggplot2)
df <- data.frame(
  group = c(0, 1, 2, 3),
  value = c(sum(dataSet$price_range==0), sum(dataSet$price_range==1), sum(dataSet$price_range==2), sum(dataSet$price_range==3))
  )
bp<- ggplot(df, aes(x="", y=value, fill=group))+
geom_bar(width = 1, stat = "identity")
bp

pie <- bp + coord_polar("y", start=0)
pie

fig(18, 16)

Correlation plot showing the features that are the most linked between each others

library(ggcorrplot)
corr <- round(cor(dataSet), 8)
ggcorrplot(corr)

fig(18, 16)
str(dataSet)
'data.frame':   2000 obs. of  21 variables:
 $ battery_power: int  842 1021 563 615 1821 1859 1821 1954 1445 509 ...
 $ blue         : int  0 1 1 1 1 0 0 0 1 1 ...
 $ clock_speed  : num  2.2 0.5 0.5 2.5 1.2 0.5 1.7 0.5 0.5 0.6 ...
 $ dual_sim     : int  0 1 1 0 0 1 0 1 0 1 ...
 $ fc           : int  1 0 2 0 13 3 4 0 0 2 ...
 $ four_g       : int  0 1 1 0 1 0 1 0 0 1 ...
 $ int_memory   : int  7 53 41 10 44 22 10 24 53 9 ...
 $ m_dep        : num  0.6 0.7 0.9 0.8 0.6 0.7 0.8 0.8 0.7 0.1 ...
 $ mobile_wt    : int  188 136 145 131 141 164 139 187 174 93 ...
 $ n_cores      : int  2 3 5 6 2 1 8 4 7 5 ...
 $ pc           : int  2 6 6 9 14 7 10 0 14 15 ...
 $ px_height    : int  20 905 1263 1216 1208 1004 381 512 386 1137 ...
 $ px_width     : int  756 1988 1716 1786 1212 1654 1018 1149 836 1224 ...
 $ ram          : int  2549 2631 2603 2769 1411 1067 3220 700 1099 513 ...
 $ sc_h         : int  9 17 11 16 8 17 13 16 17 19 ...
 $ sc_w         : int  7 3 2 8 2 1 8 3 1 10 ...
 $ talk_time    : int  19 7 9 11 15 10 18 5 20 12 ...
 $ three_g      : int  0 1 1 1 1 1 1 1 1 1 ...
 $ touch_screen : int  0 1 1 0 1 0 0 1 0 0 ...
 $ wifi         : int  1 0 0 0 0 0 1 1 0 0 ...
 $ price_range  : int  1 2 2 2 1 1 3 0 0 0 ...

Displaying the cell percentages of different features of the dataSet

prop.table(table(dataSet$blue)) # cell percentages

    0     1 
0.505 0.495 
prop.table(table(dataSet$dual_sim)) # cell percentages

     0      1 
0.4905 0.5095 
prop.table(table(dataSet$four_g)) # cell percentages

     0      1 
0.4785 0.5215 
prop.table(table(dataSet$three_g)) # cell percentages

     0      1 
0.2385 0.7615 
prop.table(table(dataSet$touch_screen)) # cell percentages

    0     1 
0.497 0.503 
prop.table(table(dataSet$wifi)) # cell percentages

    0     1 
0.493 0.507 

Comparing the impact of two features on the mobile’s price range

library(ggplot2)
data = data.frame(Dimensions_in_cm = c(dataSet$sc_h, dataSet$sc_w), 
               Screen = rep(c("Height", "Width"), c(length(dataSet$sc_h), length(dataSet$sc_w))))
ggplot(data, aes(Dimensions_in_cm, fill = Screen)) + 
  geom_bar(position = 'identity', alpha = .6)

Comparing the impact of two features on the mobile’s price range

library(ggplot2)
library(gridExtra)
dataSet$price_range <- as.factor(dataSet$price_range)
p1 <-  ggplot(dataSet, aes(x=px_width, y = px_height, color=price_range)) +
  geom_boxplot(outlier.colour="red", outlier.shape=8,
               outlier.size=4) +
  labs(title = "Pixel Resolution Height vs Pixel Resolution Width")
p2 <- ggplot(dataSet, aes(x=price_range, y = ram, color=price_range)) +
  geom_boxplot(outlier.colour="red", outlier.shape=8,
               outlier.size=4) +
  labs(title = "RAM vs Price Range")
grid.arrange(p1, p2,nrow = 1)

fig(24, 20)

Interquartile range of two features at a time

library(ggplot2)
library(gridExtra)
dataSet$price_range <- as.factor(dataSet$price_range)
p3 <- ggplot(dataSet, aes(x=price_range, y = int_memory, color=price_range)) +
  geom_boxplot(outlier.colour="red", outlier.shape=8,
               outlier.size=4) +
  labs(title = "int_memory vs Price Range")
p4 <- ggplot(dataSet, aes(x=price_range, y = battery_power, color=price_range)) +
  geom_boxplot(outlier.colour="red", outlier.shape=8,
               outlier.size=4) +
  labs(title = "Battery power vs Price Range")
grid.arrange(p3, p4,nrow = 1)

fig(24, 20)

Data classification depending on battery power, ram, memory, clock speed and number of cores

library(dplyr)
library(ggplot2)
library(gridExtra)
#Battery_power IQR
firstQuantile <- quantile(dataSet$battery_power, 0.25)
thirdQuantile <- quantile(dataSet$battery_power, 0.75)
battery_powerIQR <- dataSet %>% filter(dataSet$battery_power > firstQuantile & dataSet$battery_power < thirdQuantile)
#Int Memory IQR
firstQuantile <- quantile(dataSet$int_memory , 0.25)
thirdQuantile <- quantile(dataSet$int_memory, 0.75)
int_memoryIQR <- dataSet %>% filter(dataSet$int_memory > firstQuantile & dataSet$int_memory < thirdQuantile)
#ram IQR
firstQuantile <- quantile(dataSet$ram , 0.25)
thirdQuantile <- quantile(dataSet$ram, 0.75)
ramIQR <- dataSet %>% filter(dataSet$ram > firstQuantile & dataSet$ram < thirdQuantile)

p2 <- ggplot(ramIQR, aes(x=price_range, y = ram, color=price_range)) +
  geom_boxplot(outlier.colour="red", outlier.shape=8,
               outlier.size=4) +
  labs(title = "IQR RAM vs Price Range")

p3 <- ggplot(int_memoryIQR, aes(x=price_range, y = int_memory, color=price_range)) +
  geom_boxplot(outlier.colour="red", outlier.shape=8,
               outlier.size=4) +
  labs(title = "IQR int memory vs Price Range")

p4 <- ggplot(battery_powerIQR, aes(x=price_range, y = battery_power, color=price_range)) +
  geom_boxplot(outlier.colour="red", outlier.shape=8,
               outlier.size=4) +
  labs(title = "IQR battery power vs Price Range")
grid.arrange(p2, p3, p4,nrow = 1)

fig(24, 20)

3D graphic

install.packages("pacman")
essai de l'URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/pacman_0.5.1.tgz'
Content type 'application/x-gzip' length 379950 bytes (371 KB)
==================================================
downloaded 371 KB

The downloaded binary packages are in
    /var/folders/6g/jj4zrn8n0pv9nvlgqdvg6k500000gn/T//RtmpT1znVe/downloaded_packages
library(ggplot2)
install.packages("dplyr")
essai de l'URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/dplyr_1.0.5.tgz'
Content type 'application/x-gzip' length 1251016 bytes (1.2 MB)
==================================================
downloaded 1.2 MB

The downloaded binary packages are in
    /var/folders/6g/jj4zrn8n0pv9nvlgqdvg6k500000gn/T//RtmpT1znVe/downloaded_packages
p <- ggplot(dataSet, aes(battery_power, ram, color = price_range))+
  geom_point()
p + stat_ellipse()

p <- ggplot(dataSet, aes(int_memory, ram, color = price_range))+
  geom_point()
p + stat_ellipse()

Kmeans classifier on battery and ram for price range

library(tidyverse)
library(plotly)
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio

Attachement du package : ‘plotly’

The following object is masked from ‘package:rio’:

    export

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout
# Creating the graphic
p <- plot_ly(
  dataSet, x = dataSet$battery_power, y = dataSet$ram, z = dataSet$int_memory, 
  color = dataSet$price_range) %>%
  add_markers(size=1) %>%
  layout(
    scene = list(xaxis = list(title = 'Battery Power'),
        yaxis = list(title = 'Ram'),
        zaxis = list(title = 'Memoire interne'))
        )
p

Logistic Regression classifier on battery and ram for price range

kNN classifier on battery and ram for price range

SVM classifier on battery and ram for price range

  print(paste0(k, paste0(" nbFold, Score F : ", score)))
[1] "10 nbFold, Score F : 0.937552039966694"

Global naiveBayes test on qualifer

library(e1071)
library(MLmetrics)
percentage_of_data_for_training <- 0.90
extractDataFromDataSet <-  dataSet %>%select(1,7,14,21)
nbColumnForTraining <- nrow(extractDataFromDataSet)*percentage_of_data_for_training
nbRowForTraining <- ncol(extractDataFromDataSet)
m <- naiveBayes(
  extractDataFromDataSet[0:nbColumnForTraining,-nbRowForTraining],
  extractDataFromDataSet[0:nbColumnForTraining,nbRowForTraining],
  eps = 1)
pred_result <- predict(m, extractDataFromDataSet[nbColumnForTraining:nrow(extractDataFromDataSet),])
true_result <- extractDataFromDataSet[nbColumnForTraining:nrow(extractDataFromDataSet),ncol(extractDataFromDataSet)]
score <- F1_Score(y_pred = pred_result, y_true = true_result)
print(score)
LS0tCnRpdGxlOiAiQW5hbHl6aW5nIERhdGEgU2V0IE1vYmlsZSBQcmljZSBXaXRoIEttZWFucyBhbmQgTG9naXN0aWMgUmVncmVzc2lvbiIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKSW5pdGlhbGl6YXRpb24gYW5kIGltcG9ydCBvZiBkYXRhCgpgYGB7cn0KaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikKaW5zdGFsbC5wYWNrYWdlcygicGFjbWFuIikKaW5zdGFsbC5wYWNrYWdlcygiZHBseXIiKQppbnN0YWxsLnBhY2thZ2VzKCJwbG90bHkiKQppbnN0YWxsLnBhY2thZ2VzKCJWR0FNIikKaW5zdGFsbC5wYWNrYWdlcygnTUxtZXRyaWNzJykKCmxpYnJhcnkodGlkeXZlcnNlKQoKZmlnIDwtIGZ1bmN0aW9uKHdpZHRoLCBoZWlndGgpewogICAgIG9wdGlvbnMocmVwci5wbG90LndpZHRoID0gd2lkdGgsIHJlcHIucGxvdC5oZWlnaHQgPSBoZWlndGgpCn0KCmxpYnJhcnkocGFjbWFuKQoKcGFjbWFuOjpwX2xvYWQocGFjbWFuLGRwbHlyLCBnZ3Bsb3QyLCByaW8sIGdyaWRFeHRyYSwgc2NhbGVzLCBnZ2NvcnJwbG90LCBjYXJldCwgZTEwNzEpCgpkYXRhU2V0IDwtIHJlYWQuY3N2KCdkYXRhL3RyYWluLmNzdicpCmBgYAoKCmBgYHtyfQpuYW1lcyhkYXRhU2V0KQpgYGAKCkRpc3BsYXkgb2YgdGhlIHNldCBvZiBkYXRhLgoKQ29sdW1ucyA6IGJhdHRlcnlfcG93ZXIsIGJsdWUsIGNsb2NrX3NwZWVkLCBkdWFsX3NpbSwgZmMsIGZvdXJfZyxpbnRfbWVtb3J5LCBtX2RlcCwgbW9iaWxlX3d0LCBuX2NvcmVzLCBwYywgcHhfaGVpZ2h0LCBweF93aWR0aCwgcmFtLCBzY19oLCBzY193LCB0YWxrX3RpbWUsIHRocmVlX2csIHRvdWNoX3NjcmVlbiwgd2lmaSwgcHJpY2VfcmFuZ2UKCmJhdHRlcnlfcG93ZXI6VG90YWwgZW5lcmd5IGEgYmF0dGVyeSBjYW4gc3RvcmUgaW4gb25lIHRpbWUgbWVhc3VyZWQgaW4gbUFoCmJsdWU6SGFzIGJsdWV0b290aCBvciBub3QKY2xvY2tfc3BlZWQ6c3BlZWQgYXQgd2hpY2ggbWljcm9wcm9jZXNzb3IgZXhlY3V0ZXMgaW5zdHJ1Y3Rpb25zCmR1YWxfc2ltOkhhcyBkdWFsIHNpbSBzdXBwb3J0IG9yIG5vdApmYzpGcm9udCBDYW1lcmEgbWVnYSBwaXhlbHMKZm91cl9nOkhhcyA0RyBvciBub3QKaW50X21lbW9yeTpJbnRlcm5hbCBNZW1vcnkgaW4gR2lnYWJ5dGVzCm1fZGVwOk1vYmlsZSBEZXB0aCBpbiBjbQptb2JpbGVfd3Q6V2VpZ2h0IG9mIG1vYmlsZSBwaG9uZQpuX2NvcmVzOk51bWJlciBvZiBjb3JlcyBvZiBwcm9jZXNzb3IKcGM6UHJpbWFyeSBDYW1lcmEgbWVnYSBwaXhlbHMKcHhfaGVpZ2h0OlBpeGVsIFJlc29sdXRpb24gSGVpZ2h0CnB4X3dpZHRoOlBpeGVsIFJlc29sdXRpb24gV2lkdGgKcmFtOlJhbmRvbSBBY2Nlc3MgTWVtb3J5IGluIE1lZ2FieXRlcwpzY19oOlNjcmVlbiBIZWlnaHQgb2YgbW9iaWxlIGluIGNtCnNjX3c6U2NyZWVuIFdpZHRoIG9mIG1vYmlsZSBpbiBjbQp0YWxrX3RpbWU6bG9uZ2VzdCB0aW1lIHRoYXQgYSBzaW5nbGUgYmF0dGVyeSBjaGFyZ2Ugd2lsbCBsYXN0IHdoZW4geW91IGFyZQp0aHJlZV9nOkhhcyAzRyBvciBub3QKdG91Y2hfc2NyZWVuOkhhcyB0b3VjaCBzY3JlZW4gb3Igbm90CndpZmk6SGFzIHdpZmkgb3Igbm90CnByaWNlX3JhbmdlOiBUaGlzIGlzIHRoZSB0YXJnZXQgdmFyaWFibGUgd2l0aCB2YWx1ZSBvZiAwKGxvdyBjb3N0KSwgMShtZWRpdW0gY29zdCksIDIoaGlnaCBjb3N0KSBhbmQgMyh2ZXJ5IGhpZ2ggY29zdCkuCgpgYGB7cn0KZGltKGRhdGFTZXQpCmNsYXNzKGRhdGFTZXQpCmhlYWQoZGF0YVNldCkKc2FwcGx5KGRhdGFTZXQsIGNsYXNzKQpgYGAKCgpgYGB7cn0Kc3VtbWFyeShkYXRhU2V0KQpgYGAKCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCmRmIDwtIGRhdGEuZnJhbWUoCiAgZ3JvdXAgPSBjKDAsIDEsIDIsIDMpLAogIHZhbHVlID0gYyhzdW0oZGF0YVNldCRwcmljZV9yYW5nZT09MCksIHN1bShkYXRhU2V0JHByaWNlX3JhbmdlPT0xKSwgc3VtKGRhdGFTZXQkcHJpY2VfcmFuZ2U9PTIpLCBzdW0oZGF0YVNldCRwcmljZV9yYW5nZT09MykpCiAgKQpwaWUgPC0gYnAgKyBjb29yZF9wb2xhcigieSIsIHN0YXJ0PTApCnBpZQpmaWcoMTgsIDE2KQpgYGAKCkNvcnJlbGF0aW9uIHBsb3Qgc2hvd2luZyB0aGUgZmVhdHVyZXMgdGhhdCBhcmUgdGhlIG1vc3QgbGlua2VkIGJldHdlZW4gZWFjaCBvdGhlcnMKYGBge3J9CmxpYnJhcnkoZ2djb3JycGxvdCkKY29yciA8LSByb3VuZChjb3IoZGF0YVNldCksIDgpCmdnY29ycnBsb3QoY29ycikKZmlnKDE4LCAxNikKYGBgCgoKYGBge3J9CnN0cihkYXRhU2V0KQpgYGAKCkRpc3BsYXlpbmcgdGhlIGNlbGwgcGVyY2VudGFnZXMgb2YgZGlmZmVyZW50IGZlYXR1cmVzIG9mIHRoZSBkYXRhU2V0CmBgYHtyfQpwcm9wLnRhYmxlKHRhYmxlKGRhdGFTZXQkYmx1ZSkpICMgY2VsbCBwZXJjZW50YWdlcwpwcm9wLnRhYmxlKHRhYmxlKGRhdGFTZXQkZHVhbF9zaW0pKSAjIGNlbGwgcGVyY2VudGFnZXMKcHJvcC50YWJsZSh0YWJsZShkYXRhU2V0JGZvdXJfZykpICMgY2VsbCBwZXJjZW50YWdlcwpwcm9wLnRhYmxlKHRhYmxlKGRhdGFTZXQkdGhyZWVfZykpICMgY2VsbCBwZXJjZW50YWdlcwpwcm9wLnRhYmxlKHRhYmxlKGRhdGFTZXQkdG91Y2hfc2NyZWVuKSkgIyBjZWxsIHBlcmNlbnRhZ2VzCnByb3AudGFibGUodGFibGUoZGF0YVNldCR3aWZpKSkgIyBjZWxsIHBlcmNlbnRhZ2VzCmBgYAoKQ29tcGFyaW5nIHRoZSBpbXBhY3Qgb2YgdHdvIGZlYXR1cmVzIG9uIHRoZSBtb2JpbGUncyBwcmljZSByYW5nZQpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdyaWRFeHRyYSkKZGF0YVNldCRwcmljZV9yYW5nZSA8LSBhcy5mYWN0b3IoZGF0YVNldCRwcmljZV9yYW5nZSkKcDEgPC0gIGdncGxvdChkYXRhU2V0LCBhZXMoeD1weF93aWR0aCwgeSA9IHB4X2hlaWdodCwgY29sb3I9cHJpY2VfcmFuZ2UpKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuY29sb3VyPSJyZWQiLCBvdXRsaWVyLnNoYXBlPTgsCiAgICAgICAgICAgICAgIG91dGxpZXIuc2l6ZT00KSArCiAgbGFicyh0aXRsZSA9ICJQaXhlbCBSZXNvbHV0aW9uIEhlaWdodCB2cyBQaXhlbCBSZXNvbHV0aW9uIFdpZHRoIikKcDIgPC0gZ2dwbG90KGRhdGFTZXQsIGFlcyh4PXByaWNlX3JhbmdlLCB5ID0gcmFtLCBjb2xvcj1wcmljZV9yYW5nZSkpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5jb2xvdXI9InJlZCIsIG91dGxpZXIuc2hhcGU9OCwKICAgICAgICAgICAgICAgb3V0bGllci5zaXplPTQpICsKICBsYWJzKHRpdGxlID0gIlJBTSB2cyBQcmljZSBSYW5nZSIpCmdyaWQuYXJyYW5nZShwMSwgcDIsbnJvdyA9IDEpCmZpZygyNCwgMjApCmBgYAoKQ29tcGFyaW5nIHRoZSBpbXBhY3Qgb2YgdHdvIGZlYXR1cmVzIG9uIHRoZSBtb2JpbGUncyBwcmljZSByYW5nZQpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdyaWRFeHRyYSkKZGF0YVNldCRwcmljZV9yYW5nZSA8LSBhcy5mYWN0b3IoZGF0YVNldCRwcmljZV9yYW5nZSkKcDMgPC0gZ2dwbG90KGRhdGFTZXQsIGFlcyh4PXByaWNlX3JhbmdlLCB5ID0gaW50X21lbW9yeSwgY29sb3I9cHJpY2VfcmFuZ2UpKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuY29sb3VyPSJyZWQiLCBvdXRsaWVyLnNoYXBlPTgsCiAgICAgICAgICAgICAgIG91dGxpZXIuc2l6ZT00KSArCiAgbGFicyh0aXRsZSA9ICJpbnRfbWVtb3J5IHZzIFByaWNlIFJhbmdlIikKcDQgPC0gZ2dwbG90KGRhdGFTZXQsIGFlcyh4PXByaWNlX3JhbmdlLCB5ID0gYmF0dGVyeV9wb3dlciwgY29sb3I9cHJpY2VfcmFuZ2UpKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuY29sb3VyPSJyZWQiLCBvdXRsaWVyLnNoYXBlPTgsCiAgICAgICAgICAgICAgIG91dGxpZXIuc2l6ZT00KSArCiAgbGFicyh0aXRsZSA9ICJCYXR0ZXJ5IHBvd2VyIHZzIFByaWNlIFJhbmdlIikKZ3JpZC5hcnJhbmdlKHAzLCBwNCxucm93ID0gMSkKZmlnKDI0LCAyMCkKYGBgCgpJbnRlcnF1YXJ0aWxlIHJhbmdlIG9mIHR3byBmZWF0dXJlcyBhdCBhIHRpbWUKYGBge3J9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShncmlkRXh0cmEpCiNCYXR0ZXJ5X3Bvd2VyIElRUgpmaXJzdFF1YW50aWxlIDwtIHF1YW50aWxlKGRhdGFTZXQkYmF0dGVyeV9wb3dlciwgMC4yNSkKdGhpcmRRdWFudGlsZSA8LSBxdWFudGlsZShkYXRhU2V0JGJhdHRlcnlfcG93ZXIsIDAuNzUpCmJhdHRlcnlfcG93ZXJJUVIgPC0gZGF0YVNldCAlPiUgZmlsdGVyKGRhdGFTZXQkYmF0dGVyeV9wb3dlciA+IGZpcnN0UXVhbnRpbGUgJiBkYXRhU2V0JGJhdHRlcnlfcG93ZXIgPCB0aGlyZFF1YW50aWxlKQojSW50IE1lbW9yeSBJUVIKZmlyc3RRdWFudGlsZSA8LSBxdWFudGlsZShkYXRhU2V0JGludF9tZW1vcnkgLCAwLjI1KQp0aGlyZFF1YW50aWxlIDwtIHF1YW50aWxlKGRhdGFTZXQkaW50X21lbW9yeSwgMC43NSkKaW50X21lbW9yeUlRUiA8LSBkYXRhU2V0ICU+JSBmaWx0ZXIoZGF0YVNldCRpbnRfbWVtb3J5ID4gZmlyc3RRdWFudGlsZSAmIGRhdGFTZXQkaW50X21lbW9yeSA8IHRoaXJkUXVhbnRpbGUpCiNyYW0gSVFSCmZpcnN0UXVhbnRpbGUgPC0gcXVhbnRpbGUoZGF0YVNldCRyYW0gLCAwLjI1KQp0aGlyZFF1YW50aWxlIDwtIHF1YW50aWxlKGRhdGFTZXQkcmFtLCAwLjc1KQpyYW1JUVIgPC0gZGF0YVNldCAlPiUgZmlsdGVyKGRhdGFTZXQkcmFtID4gZmlyc3RRdWFudGlsZSAmIGRhdGFTZXQkcmFtIDwgdGhpcmRRdWFudGlsZSkKCnAyIDwtIGdncGxvdChyYW1JUVIsIGFlcyh4PXByaWNlX3JhbmdlLCB5ID0gcmFtLCBjb2xvcj1wcmljZV9yYW5nZSkpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5jb2xvdXI9InJlZCIsIG91dGxpZXIuc2hhcGU9OCwKICAgICAgICAgICAgICAgb3V0bGllci5zaXplPTQpICsKICBsYWJzKHRpdGxlID0gIklRUiBSQU0gdnMgUHJpY2UgUmFuZ2UiKQoKcDMgPC0gZ2dwbG90KGludF9tZW1vcnlJUVIsIGFlcyh4PXByaWNlX3JhbmdlLCB5ID0gaW50X21lbW9yeSwgY29sb3I9cHJpY2VfcmFuZ2UpKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuY29sb3VyPSJyZWQiLCBvdXRsaWVyLnNoYXBlPTgsCiAgICAgICAgICAgICAgIG91dGxpZXIuc2l6ZT00KSArCiAgbGFicyh0aXRsZSA9ICJJUVIgaW50IG1lbW9yeSB2cyBQcmljZSBSYW5nZSIpCgpwNCA8LSBnZ3Bsb3QoYmF0dGVyeV9wb3dlcklRUiwgYWVzKHg9cHJpY2VfcmFuZ2UsIHkgPSBiYXR0ZXJ5X3Bvd2VyLCBjb2xvcj1wcmljZV9yYW5nZSkpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5jb2xvdXI9InJlZCIsIG91dGxpZXIuc2hhcGU9OCwKICAgICAgICAgICAgICAgb3V0bGllci5zaXplPTQpICsKICBsYWJzKHRpdGxlID0gIklRUiBiYXR0ZXJ5IHBvd2VyIHZzIFByaWNlIFJhbmdlIikKZ3JpZC5hcnJhbmdlKHAyLCBwMywgcDQsbnJvdyA9IDEpCmZpZygyNCwgMjApCmBgYAoKRGF0YSBjbGFzc2lmaWNhdGlvbiBkZXBlbmRpbmcgb24gYmF0dGVyeSBwb3dlciwgcmFtLCBtZW1vcnksIGNsb2NrIHNwZWVkIGFuZCBudW1iZXIgb2YgY29yZXMKYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKcCA8LSBnZ3Bsb3QoZGF0YVNldCwgYWVzKGJhdHRlcnlfcG93ZXIsIHJhbSwgY29sb3IgPSBwcmljZV9yYW5nZSkpKwogIGdlb21fcG9pbnQoKQpwICsgc3RhdF9lbGxpcHNlKCkKcCA8LSBnZ3Bsb3QoZGF0YVNldCwgYWVzKGludF9tZW1vcnksIHJhbSwgY29sb3IgPSBwcmljZV9yYW5nZSkpKwogIGdlb21fcG9pbnQoKQpwICsgc3RhdF9lbGxpcHNlKCkKYGBgCgoKM0QgZ3JhcGhpYyAKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHBsb3RseSkKCiMgQ3JlYXRpbmcgdGhlIGdyYXBoaWMKcCA8LSBwbG90X2x5KAogIGRhdGFTZXQsIHggPSBkYXRhU2V0JGJhdHRlcnlfcG93ZXIsIHkgPSBkYXRhU2V0JHJhbSwgeiA9IGRhdGFTZXQkaW50X21lbW9yeSwgCiAgY29sb3IgPSBkYXRhU2V0JHByaWNlX3JhbmdlKSAlPiUKICBhZGRfbWFya2VycyhzaXplPTEpICU+JQogIGxheW91dCgKICAgIHNjZW5lID0gbGlzdCh4YXhpcyA9IGxpc3QodGl0bGUgPSAnQmF0dGVyeSBQb3dlcicpLAogICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICdSYW0nKSwKICAgICAgICB6YXhpcyA9IGxpc3QodGl0bGUgPSAnTWVtb2lyZSBpbnRlcm5lJykpCiAgICAgICAgKQpwCmBgYAoKS21lYW5zIGNsYXNzaWZpZXIgb24gYmF0dGVyeSBhbmQgcmFtIGZvciBwcmljZSByYW5nZQpgYGB7cn0KbGlicmFyeShNTG1ldHJpY3MpCgpleHRyYWN0RGF0YUZyb21EYXRhU2V0IDwtICBkYXRhU2V0ICU+JXNlbGVjdCgxLCAxNCwgMjEpICMgYmF0dGVyeSA9IDEgLG1lbW9yeSA9IDcsIHJhbSA9IDE0LCBtb2JpbGUgY2xhc3MgPSAyMQpleHRyYWN0RGF0YUZyb21EYXRhU2V0JHByaWNlX3JhbmdlCnRlbXBvIDwtIGFzLm51bWVyaWMoZXh0cmFjdERhdGFGcm9tRGF0YVNldCRwcmljZV9yYW5nZSkKdGVtcG8KZXh0cmFjdERhdGFGcm9tRGF0YVNldCRwcmljZV9yYW5nZSA8LSB0ZW1wbwpleHRyYWN0RGF0YUZyb21EYXRhU2V0JHByaWNlX3JhbmdlCnNldC5zZWVkKDEwMSkKZXh0cmFjdERhdGFGcm9tRGF0YVNldFssMToyXQpnZ3Bsb3QoZXh0cmFjdERhdGFGcm9tRGF0YVNldCxhZXMoeCA9IGV4dHJhY3REYXRhRnJvbURhdGFTZXQkYmF0dGVyeV9wb3dlciwgeSA9IGV4dHJhY3REYXRhRnJvbURhdGFTZXQkcmFtLCBjb2w9IGV4dHJhY3REYXRhRnJvbURhdGFTZXQkcHJpY2VfcmFuZ2UpKSArIGdlb21fcG9pbnQoKQpkYXRhQ2x1c3RlciA8LSBrbWVhbnMoZXh0cmFjdERhdGFGcm9tRGF0YVNldFssMToyXSwgY2VudGVyPTQsIG5zdGFydD0xMDApCmRhdGFDbHVzdGVyCmRhdGFDbHVzdGVyJGNsdXN0ZXIKZGF0YUNsdXN0ZXIkY2x1c3RlciA8LSBkYXRhQ2x1c3RlciRjbHVzdGVyIC0gMQpleHRyYWN0RGF0YUZyb21EYXRhU2V0JHByaWNlX3JhbmdlIDwtIGV4dHJhY3REYXRhRnJvbURhdGFTZXQkcHJpY2VfcmFuZ2UtMQpkYXRhQ2x1c3RlciRjbHVzdGVyCnRhYmxlKGRhdGFDbHVzdGVyJGNsdXN0ZXIsIGV4dHJhY3REYXRhRnJvbURhdGFTZXQkcHJpY2VfcmFuZ2UpCmxpYnJhcnkoY2x1c3RlcikKY2x1c3Bsb3QoZXh0cmFjdERhdGFGcm9tRGF0YVNldCwgZGF0YUNsdXN0ZXIkY2x1c3RlciwgY29sb3I9VCwgc2hhZGU9VCwgbGFiZWxzPTAsIGxpbmVzPTApCgpzY29yZSA8LSBGMV9TY29yZSh5X3ByZWQgPSBkYXRhQ2x1c3RlciRjbHVzdGVyLCB5X3RydWUgPSBleHRyYWN0RGF0YUZyb21EYXRhU2V0JHByaWNlX3JhbmdlKQpwcmludChwYXN0ZTAoIlNjb3JlIEYgOiAiLCBzY29yZSkpCmBgYAoKTG9naXN0aWMgUmVncmVzc2lvbiBjbGFzc2lmaWVyIG9uIGJhdHRlcnkgYW5kIHJhbSBmb3IgcHJpY2UgcmFuZ2UKYGBge3J9CmxpYnJhcnkoVkdBTSkKc2VlZCA8LSAxODA5CnNldC5zZWVkKHNlZWQpCgpsaWJyYXJ5KGNhcmV0KSAjIEZvciB0aGUgY29uZnVzaW9uIG1hdHJpeApsaWJyYXJ5KE1MbWV0cmljcykKCm4gPC0gbnJvdyhkYXRhU2V0KQojIFNlbGVjdCBvbmx5IHRoZSByZWxldmFudCB2YXJpYWJsZXMKUmVkdWNlZERhdGFTZXQgPC0gc3Vic2V0KGRhdGFTZXQsIHNlbGVjdD1jKCJiYXR0ZXJ5X3Bvd2VyIiwgInJhbSIsICJwcmljZV9yYW5nZSIpKQoKIyBEZWZpbmUgdGhlIGZvbGRzCm5fZm9sZHMgPC0gMTAgIyBudW1iZXIgb2YgZm9sZHMKZm9sZHNfaSA8LSBzYW1wbGUocmVwKDE6bl9mb2xkcywgbGVuZ3RoLm91dCA9IG4pKSAjIGdlbmVyYXRlIHRoZSBmb2xkcwoKIyBJbml0aWFsaXphdGlvbiBvZiB0aGUgb3V0cHV0cwphY2N1cmFjeSA8LSBtYXRyaXgoTkEsIG5yb3cgPSBuX2ZvbGRzLCBuY29sID0gMSkKc2Vuc2l0aXZpdHkgPC0gbWF0cml4KE5BLCBucm93ID0gbl9mb2xkcywgbmNvbCA9IDEpCnNwZWNpZmljaXR5IDwtIG1hdHJpeChOQSwgbnJvdyA9IG5fZm9sZHMsIG5jb2wgPSAxKQoKZm9yIChrIGluIDE6bl9mb2xkcykgewogIHRlc3RfaSA8LSB3aGljaChmb2xkc19pID09IGspCgogICMgUHJlcGFyZSB0aGUgZm9sZCBkYXRhc2V0cyAodHJhaW4gYW5kIHRlc3QpCiAgdHJhaW5mb2xkIDwtIFJlZHVjZWREYXRhU2V0Wy10ZXN0X2ksIF0KICB0ZXN0Zm9sZCA8LSBSZWR1Y2VkRGF0YVNldFt0ZXN0X2ksIF0KICAKICAjIE5vdyBmZWVkIGl0IHRvIHZnbG0KICBmaXR0ZWRfbW9kZWwgPC0gdmdsbShmb3JtdWxhID0gcHJpY2VfcmFuZ2UgfiAgLiAsIGRhdGE9dHJhaW5mb2xkLCBmYW1pbHk9bXVsdGlub21pYWwpCiAgCiAgcHJlZGljdGlvbnM9cHJlZGljdChmaXR0ZWRfbW9kZWwsIHRlc3Rmb2xkLCB0eXBlID0icmVzcG9uc2UiKQogIHByZWRpY3Rpb25zCiAgcHJlZGljdGlvbnMucmVzdWx0cyA8LSBpZmVsc2UocHJlZGljdGlvbnMgPiAwLjUsICJ5ZXMiLCAibm8iKSAjIHRyYW5zZm9ybSB0aGUgb3V0cHV0IGluICJ5ZXMvbm8iCiAgcHJlZGljdGlvbnMucmVzdWx0cwogIAogIHRydWVfcmVzdWx0X3ByaWNlX3JhbmdlIDwtIHByZWRpY3Rpb25zLnJlc3VsdHMgIyBjb3B5IHRvIGdldCB0aGUgCiAgdHJ1ZV9yZXN1bHRfcHJpY2VfcmFuZ2VbLDFdIDwtIGlmZWxzZSh0ZXN0Zm9sZFssM10gPT0gMCwgInllcyIsICJubyIpICMgdHJhbnNmb3JtIHRoZSBvdXRwdXQgaW4gInllcy9ubyIKICB0cnVlX3Jlc3VsdF9wcmljZV9yYW5nZVssMl0gPC0gaWZlbHNlKHRlc3Rmb2xkWywzXSA9PSAxLCAieWVzIiwgIm5vIikgIyB0cmFuc2Zvcm0gdGhlIG91dHB1dCBpbiAieWVzL25vIgogIHRydWVfcmVzdWx0X3ByaWNlX3JhbmdlWywzXSA8LSBpZmVsc2UodGVzdGZvbGRbLDNdID09IDIsICJ5ZXMiLCAibm8iKSAjIHRyYW5zZm9ybSB0aGUgb3V0cHV0IGluICJ5ZXMvbm8iCiAgdHJ1ZV9yZXN1bHRfcHJpY2VfcmFuZ2VbLDRdIDwtIGlmZWxzZSh0ZXN0Zm9sZFssM10gPT0gMywgInllcyIsICJubyIpICMgdHJhbnNmb3JtIHRoZSBvdXRwdXQgaW4gInllcy9ubyIKICAKICB0cnVlX3Jlc3VsdF9wcmljZV9yYW5nZQogIAogICMgQ29tcHV0ZSB0aGUgY29uZnVzaW9uIG1hdHJpeCBhbmQgdGhlIGFjY3VyYWN5CiAgY00gPC0gY29uZnVzaW9uTWF0cml4KGFzLmZhY3RvcihwcmVkaWN0aW9ucy5yZXN1bHRzKSwgYXMuZmFjdG9yKHRydWVfcmVzdWx0X3ByaWNlX3JhbmdlKSwgcG9zaXRpdmUgPSAieWVzIikKICBjTQogIGFjY3VyYWN5W2tdIDwtIGNNJG92ZXJhbGxbMV0KICBzZW5zaXRpdml0eVtrXSA8LSBjTSRieUNsYXNzWzFdICMgdHJ1ZSBwb3NpdGl2ZSByYXRlCiAgc3BlY2lmaWNpdHlba10gPC0gY00kYnlDbGFzc1syXSAjIHRydWUgbmVnYXRpdmUgcmF0ZQogIAogIHNjb3JlIDwtIEYxX1Njb3JlKHlfcHJlZCA9IHByZWRpY3Rpb25zLnJlc3VsdHMsIHlfdHJ1ZSA9IHRydWVfcmVzdWx0X3ByaWNlX3JhbmdlKQogIHByaW50KHBhc3RlMChrLCBwYXN0ZTAoIiBuYkZvbGQsIFNjb3JlIEYgOiAiLCBzY29yZSkpKQp9CgoKIyBQbG90IHRoZSBhY2N1cmFjeSwgdGhlIGZhbHNlIG5lZ2F0aXZlIHJhdGUgYW5kIHRoZSBmYWxzZSBwb3NpdGl2ZSByYXRlCnBhcihtZnJvdyA9IGMoMiwgMikpICMgcGxvdCB0aGUgcmVzdWx0cyBvbiB0aGUgc2FtZSBmaWd1cmUKCnBsdDEgPC0gcGxvdChzZXEoMSxuX2ZvbGRzKSwgYWNjdXJhY3ksIAogICAgIHR5cGUgPSAibCIsIGx3ZCA9IDIsIGNvbCA9ICJibHVlIiwgCiAgICAgeWxhYiA9ICJBY2N1cmFjeSIsIHhsYWIgPSAiRm9sZCBudW1iZXIiLCAKICAgICBtYWluID0gcGFzdGUwKG5fZm9sZHMsICItZm9sZCBDcm9zcy1WYWxpZGF0aW9uIiksIAogICAgIHlsaW0gPSBjKDAuMDEsIDEpIAogICAgICkKCnBsdDI8LXBsb3Qoc2VxKDEsbl9mb2xkcyksIDEtc2Vuc2l0aXZpdHksIAogICAgIHR5cGUgPSAibCIsIGx3ZCA9IDIsIGNvbCA9ICJyZWQiLCAKICAgICB5bGFiID0gIkZhbHNlIG5lZ2F0aXZlIHJhdGUiLCB4bGFiID0gIkZvbGQgbnVtYmVyIiwgCiAgICAgbWFpbiA9IHBhc3RlMChuX2ZvbGRzLCAiLWZvbGQgQ3Jvc3MtVmFsaWRhdGlvbiIpLCAKICAgICB5bGltID0gYygwLjAxLCAxKSAKKQoKcGx0MzwtcGxvdChzZXEoMSxuX2ZvbGRzKSwgMS1zcGVjaWZpY2l0eSwgCiAgICAgdHlwZSA9ICJsIiwgbHdkID0gMiwgY29sID0gImdyZWVuIiwgCiAgICAgeWxhYiA9ICJGYWxzZSBwb3NpdGl2ZSByYXRlIiwgeGxhYiA9ICJGb2xkIG51bWJlciIsIAogICAgIG1haW4gPSBwYXN0ZTAobl9mb2xkcywgIi1mb2xkIENyb3NzLVZhbGlkYXRpb24iKSwgCiAgICAgeWxpbSA9IGMoMC4wMSwgMSkgCikKCmBgYAoKa05OIGNsYXNzaWZpZXIgb24gYmF0dGVyeSBhbmQgcmFtIGZvciBwcmljZSByYW5nZQpgYGB7cn0KbGlicmFyeShWR0FNKQpsaWJyYXJ5KGNsYXNzKQpzZWVkIDwtIDE4MDkKc2V0LnNlZWQoc2VlZCkKCmxpYnJhcnkoY2FyZXQpICMgRm9yIHRoZSBjb25mdXNpb24gbWF0cml4CmxpYnJhcnkoTUxtZXRyaWNzKQoKbiA8LSBucm93KGRhdGFTZXQpCiMgU2VsZWN0IG9ubHkgdGhlIHJlbGV2YW50IHZhcmlhYmxlcwpSZWR1Y2VkRGF0YVNldCA8LSBzdWJzZXQoZGF0YVNldCwgc2VsZWN0PWMoImJhdHRlcnlfcG93ZXIiLCAicmFtIiwgInByaWNlX3JhbmdlIikpCgojIERlZmluZSB0aGUgZm9sZHMKbl9mb2xkcyA8LSAxMCAjIG51bWJlciBvZiBmb2xkcwpmb2xkc19pIDwtIHNhbXBsZShyZXAoMTpuX2ZvbGRzLCBsZW5ndGgub3V0ID0gbikpICMgZ2VuZXJhdGUgdGhlIGZvbGRzCgojIEluaXRpYWxpemF0aW9uIG9mIHRoZSBvdXRwdXRzCmFjY3VyYWN5IDwtIG1hdHJpeChOQSwgbnJvdyA9IG5fZm9sZHMsIG5jb2wgPSAxKQpzZW5zaXRpdml0eSA8LSBtYXRyaXgoTkEsIG5yb3cgPSBuX2ZvbGRzLCBuY29sID0gMSkKc3BlY2lmaWNpdHkgPC0gbWF0cml4KE5BLCBucm93ID0gbl9mb2xkcywgbmNvbCA9IDEpCgpmb3IgKGsgaW4gMTpuX2ZvbGRzKSB7CiAgdGVzdF9pIDwtIHdoaWNoKGZvbGRzX2kgPT0gaykKCiAgIyBQcmVwYXJlIHRoZSBmb2xkIGRhdGFzZXRzICh0cmFpbiBhbmQgdGVzdCkKICB0cmFpbmZvbGQgPC0gUmVkdWNlZERhdGFTZXRbLXRlc3RfaSwgXQogIHRlc3Rmb2xkIDwtIFJlZHVjZWREYXRhU2V0W3Rlc3RfaSwgXQogIAogICMgTm93IGZlZWQgaXQgdG8gdmdsbQogICNmaXR0ZWRfbW9kZWwgPC0gdmdsbShmb3JtdWxhID0gcHJpY2VfcmFuZ2UgfiAgLiAsIGRhdGE9dHJhaW5mb2xkLCBmYW1pbHk9bXVsdGlub21pYWwpCiAgCiAgZml0dGVkX21vZGVsIDwtIGtubih0cmFpbmZvbGRbLDE6Ml0sIHRlc3Rmb2xkWywxOjJdLCB0cmFpbmZvbGQkcHJpY2VfcmFuZ2UsIGs9MykKICBjb25mdXNpb24gPC0gdGFibGUoZml0dGVkX21vZGVsLCB0ZXN0Zm9sZCRwcmljZV9yYW5nZSkKICBjb25mdXNpb24KICAKICBzY29yZSA8LSBGMV9TY29yZSh5X3ByZWQgPSBmaXR0ZWRfbW9kZWwsIHlfdHJ1ZSA9IHRlc3Rmb2xkJHByaWNlX3JhbmdlKQogIHByaW50KHBhc3RlMChrLCBwYXN0ZTAoIiBuYkZvbGQsIFNjb3JlIEYgOiAiLCBzY29yZSkpKQp9CgojIENyZWF0ZSBhIGRhdGFmcmFtZSB0byBzaW1wbGlmeSBjaGFydGluZwpwbG90LmRmID0gZGF0YS5mcmFtZSh0ZXN0Zm9sZCwgcHJlZGljdGVkID0gZml0dGVkX21vZGVsKQoKIyBVc2UgZ2dwbG90CiMgMi1EIHBsb3RzIGV4YW1wbGUgb25seQojIFNlcGFsLkxlbmd0aCB2cyBTZXBhbC5XaWR0aAoKIyBGaXJzdCB1c2UgQ29udmV4IGh1bGwgdG8gZGV0ZXJtaW5lIGJvdW5kYXJ5IHBvaW50cyBvZiBlYWNoIGNsdXN0ZXIKcGxvdC5kZjEgPSBkYXRhLmZyYW1lKHggPSBwbG90LmRmJGJhdHRlcnlfcG93ZXIsIAogICAgICAgICAgICAgICAgICAgICAgeSA9IHBsb3QuZGYkcmFtLCAKICAgICAgICAgICAgICAgICAgICAgIHRydWUgPSBwbG90LmRmJHByaWNlX3JhbmdlLAogICAgICAgICAgICAgICAgICAgICAgcHJlZGljdGVkID0gcGxvdC5kZiRwcmljZV9yYW5nZSkKCmZpbmRfaHVsbCA9IGZ1bmN0aW9uKGRmKSBkZltjaHVsbChkZiR4LCBkZiR5KSwgXQpib3VuZGFyeSA9IGRkcGx5KHBsb3QuZGYxLCAudmFyaWFibGVzID0gInByZWRpY3RlZCIsIC5mdW4gPSBmaW5kX2h1bGwpCgoKZ2dwbG90KHBsb3QuZGYsIGFlcyhiYXR0ZXJ5X3Bvd2VyLCByYW0sIGNvbG9yID0gcHJlZGljdGVkLCBmaWxsID0gcHJlZGljdGVkKSkgKyAKICBnZW9tX3BvaW50KHNpemUgPSA1KSArIAogIGdlb21fcG9seWdvbihkYXRhID0gYm91bmRhcnksIGFlcyh4LHkpLCBhbHBoYSA9IDAuNSkKYGBgCgpTVk0gY2xhc3NpZmllciBvbiBiYXR0ZXJ5IGFuZCByYW0gZm9yIHByaWNlIHJhbmdlCmBgYHtyfQpsaWJyYXJ5KGUxMDcxKQoKZXh0cmFjdERhdGFGcm9tRGF0YVNldCA8LSAgZGF0YVNldCAlPiUgc2VsZWN0KDEsIDE0LCAyMSkKCiMgZMOpY2xhcmF0aW9uIGRlcyBkb25uw6llcwojIGxlIG1vZMOobGUgZXN0IGNhbGN1bMOpIGF2ZWMgbGVzIHZhbGV1cnMKIyBwYXIgZMOpZmF1dCBkZXMgcGFyYW3DqHRyZXMKIyAobm95YXUgZ2F1c3NpZW4sIHDDqW5hbGlzYXRpb24gw6AgMSwgZ2FtbWE9MCwyNSkKbW9kZWwgPSBzdm0ocHJpY2VfcmFuZ2UgfiAuLCBkYXRhID0gZXh0cmFjdERhdGFGcm9tRGF0YVNldCkKcHJpbnQobW9kZWwpCnN1bW1hcnkobW9kZWwpCgojIHByw6l2aXNpb24gZGUgbCfDqWNoYW50aWxsb24gZCdhcHByZW50aXNzYWdlCnByZWQgPSBwcmVkaWN0KG1vZGVsLCBleHRyYWN0RGF0YUZyb21EYXRhU2V0WywxOjJdKQoKIyBNYXRyaWNlIGRlIGNvbmZ1c2lvbiBwb3VyIGwnw6ljaGFudGlsbG9uCiMgZCdhcHByZW50aXNzYWdlCgp0YWJsZShwcmVkLCBleHRyYWN0RGF0YUZyb21EYXRhU2V0JHByaWNlX3JhbmdlKQojIFZpc3VhbGlzYXRpb24gZGVzIGNsYXNzZXMgKGNvdWxldXJzKQojIGV0IGRlcyB2ZWN0ZXVycyBzdXBwb3J0cyAoIisiKQoKc2NvcmUgPC0gRjFfU2NvcmUoeV9wcmVkID0gcHJlZCwgeV90cnVlID0gZXh0cmFjdERhdGFGcm9tRGF0YVNldCRwcmljZV9yYW5nZSkKcHJpbnQocGFzdGUwKCIgbmJGb2xkLCBTY29yZSBGIDogIiwgc2NvcmUpKQoKcGxvdChjbWRzY2FsZShkaXN0KGV4dHJhY3REYXRhRnJvbURhdGFTZXRbLC0zXSkpLApjb2wgPSBhcy5pbnRlZ2VyKGV4dHJhY3REYXRhRnJvbURhdGFTZXRbLDNdKSwKcGNoID0gYygibyIsIisiLCAiLSIsICJ4IilbMToxNTAgJWluJSBtb2RlbCRpbmRleCArIDFdKQpgYGAKCkdsb2JhbCBuYWl2ZUJheWVzIHRlc3Qgb24gcXVhbGlmZXIKYGBge3J9CmxpYnJhcnkoZTEwNzEpCmxpYnJhcnkoTUxtZXRyaWNzKQpwZXJjZW50YWdlX29mX2RhdGFfZm9yX3RyYWluaW5nIDwtIDAuOTAKZXh0cmFjdERhdGFGcm9tRGF0YVNldCA8LSAgZGF0YVNldCAlPiVzZWxlY3QoMSw3LDE0LDIxKQpuYkNvbHVtbkZvclRyYWluaW5nIDwtIG5yb3coZXh0cmFjdERhdGFGcm9tRGF0YVNldCkqcGVyY2VudGFnZV9vZl9kYXRhX2Zvcl90cmFpbmluZwpuYlJvd0ZvclRyYWluaW5nIDwtIG5jb2woZXh0cmFjdERhdGFGcm9tRGF0YVNldCkKbSA8LSBuYWl2ZUJheWVzKAogIGV4dHJhY3REYXRhRnJvbURhdGFTZXRbMDpuYkNvbHVtbkZvclRyYWluaW5nLC1uYlJvd0ZvclRyYWluaW5nXSwKICBleHRyYWN0RGF0YUZyb21EYXRhU2V0WzA6bmJDb2x1bW5Gb3JUcmFpbmluZyxuYlJvd0ZvclRyYWluaW5nXSwKICBlcHMgPSAxKQpwcmVkX3Jlc3VsdCA8LSBwcmVkaWN0KG0sIGV4dHJhY3REYXRhRnJvbURhdGFTZXRbbmJDb2x1bW5Gb3JUcmFpbmluZzpucm93KGV4dHJhY3REYXRhRnJvbURhdGFTZXQpLF0pCnRydWVfcmVzdWx0IDwtIGV4dHJhY3REYXRhRnJvbURhdGFTZXRbbmJDb2x1bW5Gb3JUcmFpbmluZzpucm93KGV4dHJhY3REYXRhRnJvbURhdGFTZXQpLG5jb2woZXh0cmFjdERhdGFGcm9tRGF0YVNldCldCnNjb3JlIDwtIEYxX1Njb3JlKHlfcHJlZCA9IHByZWRfcmVzdWx0LCB5X3RydWUgPSB0cnVlX3Jlc3VsdCkKcHJpbnQoc2NvcmUpCmBgYA==